package com.cyy.common.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.http.useragent.Browser;
import cn.hutool.http.useragent.UserAgent;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cyy.common.constant.CommentSource;
import com.cyy.common.constant.CommentType;
import com.cyy.common.constant.Constants;
import com.cyy.common.domain.BaseEntity;
import com.cyy.common.exception.ProcessException;
import com.cyy.common.mapper.CommentMapper;
import com.cyy.common.pojo.dto.CommentLikeDto;
import com.cyy.common.pojo.dto.CommentTreeDto;
import com.cyy.common.pojo.vo.api.ApiMessageVo;
import com.cyy.common.pojo.entity.Comment;
import com.cyy.common.pojo.req.CommentAddReq;
import com.cyy.common.pojo.resp.CommentTreeResp;
import com.cyy.common.service.CommentService;
import com.cyy.common.utils.CommentUtils;
import com.cyy.common.utils.IpUtils;
import com.cyy.common.utils.PageUtils;
import com.cyy.common.utils.RequestContextUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 评论表 服务实现类
 * </p>
 *
 * @author 曹云友
 * @since 2024-04-01
 */
@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {


    public CommentTreeResp treeHandler(List<CommentTreeDto> commentNodes) {
        CommentTreeDto preNode = new CommentTreeDto();
        preNode.setId(0);
        HashSet<Integer> visited = new HashSet<>();
        int count = 0;
        CommentUtils.generatorTreeAndCount(commentNodes, preNode, visited, count);

        // 清空
        commentNodes.clear();
        visited.clear();

        // 结果组床
        CommentTreeResp resp = new CommentTreeResp();
        resp.setCommentCount(count);
        resp.setCommentTrees(preNode.getChildren());
        return resp;
    }


    @Override
    public CommentTreeResp treeByType(String sourceType, Long articleId) {
        List<CommentTreeDto> commentNodes = baseMapper.listByType(sourceType, articleId);
        // 是否点赞判断
        // 1. 判断是否登录
        this.isClickHandle(commentNodes, CommentType.LIKE);
        this.isClickHandle(commentNodes, CommentType.DISLIKE);

        return treeHandler(commentNodes);
    }

    private void isClickHandle(List<CommentTreeDto> commentNodes, CommentType currType) {
        if (StpUtil.isLogin()) {
            // 1. 拿出所有的ID
            List<Integer> commentIds = commentNodes.stream().map(CommentTreeDto::getId).collect(Collectors.toList());
            // 2. 查询当前用户点赞的ID列表
            List<Comment> clickComments = baseMapper.selectList(Wrappers.<Comment>lambdaQuery()
                    .select(Comment::getParentId)
                    .eq(Comment::getUserId, StpUtil.getLoginIdAsInt())
                    .in(Comment::getParentId, commentIds)
                    .eq(Comment::getType, currType.getCode())
                    .eq(BaseEntity::getStatus, Boolean.TRUE)
            );
            if (CollectionUtil.isNotEmpty(clickComments)) {
                Set<Integer> clickCommentIds = clickComments.stream()
                        .map(Comment::getParentId)
                        .collect(Collectors.toSet());
                if (currType.equals(CommentType.LIKE)) {
                    commentNodes.forEach(i -> {
                        i.setClickLike(clickCommentIds.contains(i.getId()));
                    });
                }
                if (currType.equals(CommentType.DISLIKE)) {
                    commentNodes.forEach(i -> {
                        i.setClickDislike(clickCommentIds.contains(i.getId()));
                    });
                }

            }
        }
    }

    @Override
    public void addComment(CommentAddReq req) {
        //判断是否需要登录
        if (CommentSource.needLogin(req.getSource())){
            StpUtil.checkLogin();
        }
        Comment comment = new Comment();
        BeanUtils.copyProperties(req, comment);
        if (StpUtil.isLogin()){
            comment.setUserId(StpUtil.getLoginIdAsInt());
        }
        if (req.getParentId() != null) {
            comment.setReplyUserId(baseMapper.selectById(req.getParentId()).getUserId());
        }
        //来源判断
        comment.setSource(req.getSource());

        // IP属地、浏览器、浏览器版本、系统、系统版本 设置
        commentWebInfoSet(comment);

        baseMapper.insert(comment);
    }

    /**
     * 评论关联的网络信息设置
     *
     * @param comment
     */
    private static void commentWebInfoSet(Comment comment) {
        HttpServletRequest request = RequestContextUtils.getRequest();
        if (Objects.nonNull(request)) {
            UserAgent userAgent = IpUtils.getUserAgent(request);
            Browser browser = userAgent.getBrowser();
            comment.setIpAddress(IpUtils.getIp2region(IpUtils.getIpAddr(request)));
            comment.setBrowser(browser.getName());
            comment.setBrowserVersion(userAgent.getVersion());
            comment.setSystem(userAgent.getPlatform().getName());
            comment.setSystemVersion(userAgent.getOsVersion());
        }
    }

    @Override
    public void deleteComment(String ids) {
        List<String> idList = Arrays.asList(ids.split(Constants.COMMA));

        if (CollectionUtil.isNotEmpty(idList)) {
            baseMapper.update(Wrappers.<Comment>lambdaUpdate()
                    .set(BaseEntity::getStatus, Boolean.FALSE)
                    .in(BaseEntity::getId, idList));
        }

    }

    @Override
    public IPage<ApiMessageVo> queryMessagePage(Integer startIndex) {
        IPage<ApiMessageVo> res = baseMapper.queryMessagePage(PageUtils.getPage(),startIndex);

        List<ApiMessageVo> records = res.getRecords();
        if (CollectionUtil.isNotEmpty(records)) {
            // 查询出对应的ID列表
            List<Integer> messageIds = records.stream().map(ApiMessageVo::getId).collect(Collectors.toList());
            // 通过ID列表查询出对应的点赞数量
            List<CommentLikeDto> likeCount = baseMapper.queryLikeCount(messageIds);
            // 处理 - 给对应的记录增加点赞信息
            if (CollectionUtil.isNotEmpty(likeCount)) {
                Map<Integer, Integer> likeDtoMap = likeCount.stream()
                        .collect(Collectors.groupingBy(CommentLikeDto::getParentId,
                                Collectors.collectingAndThen(Collectors.toList(), value -> value.get(0).getLikeCount())));

                if (MapUtil.isNotEmpty(likeDtoMap)) {
                    records.forEach(i -> {
                        i.setLikeCount(likeDtoMap.get(i.getId()));
                    });
                }
            }
            // 通过ID查询当前用户是否点过赞
            if (StpUtil.isLogin()) {
                // 当前用户点赞记录
                List<Integer> clickLikeRecordIds = baseMapper.queryClickLikeRecord(messageIds, StpUtil.getLoginId());
                records.forEach(i -> {
                    i.setClickLike(clickLikeRecordIds.contains(i.getId()));

                    // 是否是当前用户
                    if (Objects.nonNull(i.getUserId())){
                        i.setIsMe(StpUtil.getLoginIdAsInt() == i.getUserId());
                    }

                });

            }
        }
        return res;
    }

    @Override
    public void clickLike(Integer commentId) {
        clickHandle(commentId, CommentType.LIKE, CommentType.DISLIKE);
    }

    @Override
    public void clickDislike(Integer commentId) {
        clickHandle(commentId, CommentType.DISLIKE, CommentType.LIKE);
    }

    /**
     * 点击操作
     *
     * @param commentId
     * @param currType
     * @param deleteType
     */
    private void clickHandle(Integer commentId, CommentType currType, CommentType deleteType) {
        // 查询是否存在对应的评论信息
        Comment comment = Optional.ofNullable(baseMapper.selectById(commentId))
                .orElseThrow(() -> new ProcessException("您所操作的评论不存在"));
        // 先删除对应的点赞信息
        baseMapper.delete(Wrappers.<Comment>lambdaQuery()
                .eq(Comment::getParentId, commentId)
                .eq(Comment::getType, deleteType.getCode())
                .eq(Comment::getUserId, StpUtil.getLoginIdAsInt())
        );

        //查询是否存在对应的点赞记录 如果有就删除
        Comment historyRecord = baseMapper.selectOne(Wrappers.<Comment>lambdaQuery()
                .eq(Comment::getParentId, commentId)
                .eq(Comment::getType, currType.getCode())
                .eq(Comment::getUserId, StpUtil.getLoginIdAsInt())
                .last(Constants.LIMIT_1)
        );


        if (Objects.nonNull(historyRecord)) {
            baseMapper.deleteById(historyRecord);
            return;
        }

        // 如果没有就添加
        Comment subComment = new Comment();
        subComment.setParentId(commentId);
        subComment.setSource(comment.getSource());
        subComment.setUserId(StpUtil.getLoginIdAsInt());
        subComment.setReplyUserId(comment.getUserId());
        subComment.setType(currType.getCode());

        // IP属地、浏览器、浏览器版本、系统、系统版本 设置
        commentWebInfoSet(subComment);

        this.save(subComment);
    }


}
